
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define PACKET_SIZE_MAX	1428
#define BUFLEN		512

int writesize=0;
int writedsize=0;

static int writeFile(char *buf,int len,char *path,char *type)
{
	FILE *fp=NULL;
	
	fp = fopen(path,type);
	if(fp == NULL){
		printf("fopen error\n");
		return -1;
	}
	
	fwrite(buf,len,1,fp);
	fclose(fp);
	writedsize += len;
	//printf("\r    %.2f%%",(float)writedsize/writesize*100);
	return 1;
}

static inline int
connect_http(const char *hostname, const int port)
{
	struct	sockaddr_in addr;
	struct	hostent *host;
	int s=0, ret = 0, err = 0;

	if((host = gethostbyname(hostname)) == NULL) {
		err = -1;
		ret = -1;
		goto FX_EXIT;
	}
	addr.sin_family	=	AF_INET;
	addr.sin_port	=	htons(port);

	addr.sin_addr	=	*(struct in_addr*)host->h_addr;

	s = socket(AF_INET, SOCK_STREAM, 0);
	if(s == -1) {
		err = -2;
		ret = -1;
		goto FX_EXIT;
	}

	if(connect(s, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
		err = -3;
		ret = -1;
		goto FX_EXIT;
	}
	printf("    Connect %s(%d) OK....\n", hostname, port);
FX_EXIT:
	if( ret < 0 ){
		printf("connect_http:error(%d), host:%s, port:%d\n", err,hostname, port);
		return ret;
	}
	return s;
}

static int
request_http(const int s,char *hostname, char *file)
{
	int ret = 0, err = 0;
	char *message = NULL;
        
	message = malloc(PACKET_SIZE_MAX);
	if( message == NULL ){
		err = -6;
		ret = -1;
		goto FX_EXIT;
	}
	memset(message, 0, PACKET_SIZE_MAX);
	
	(void)snprintf(message, BUFLEN, "GET /%s HTTP/1.0\r\n"
		"Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg\r\n"
		"Accept-Language: zh-tw\r\n"
		"User-Agent: Mozilla/4.0\r\n"
		"Accept-Encoding: gzip, deflate\r\n"
		"Host: %s\r\n"
		"Connection: Keep-Alive\r\n"
		"Cookie: __utmc=20101124\r\n\r\n"
		, file,hostname);
	if(write(s, message, strlen(message)) == -1) {
		err = -1;
		ret = -1;
		goto FX_EXIT;
	}
	
FX_EXIT:
	if( message != NULL ){
		printf("    request_http() success\n");
		free(message);
	}
	if( ret < 0 ){
		printf("request_http:error(%d), sock:%d, file:%s\n", err,
			s, file);
	}
	return ret;
        
}

void set_tv(struct timeval *tv,int tv_sec,int tv_usec)
{
	tv->tv_sec = tv_sec;
	tv->tv_usec = tv_usec;
}

static int
//read_http(int s, char *name, char **firmwareUrl)
read_http(int s,char *path)
{
	int n, ret = 0, err = 0,h=0;
	char *server_msg = NULL;
	char *ptr1 = NULL, *ptr2 = NULL, *namePtr = NULL;
	fd_set t_set1;
	struct timeval tv;
	char Content_Type[50]={0};
	int Content_Length=0;
	int packet_cnt=0;
	
	server_msg = malloc(PACKET_SIZE_MAX);
	if( server_msg == NULL ){
		err = -6;
		ret = -1;
		goto FX_EXIT;
	}
	
	set_tv(&tv,5,0);
	
	FD_ZERO(&t_set1);
	FD_SET(s, &t_set1);
	
	sleep(1);
	while(1)
	{
		h= select(s+1, &t_set1, NULL, NULL, &tv);
		if(h<=0)
		{
			close(s);
			goto FX_EXIT;
		}
		if(h>0)
		{
			memset(server_msg, 0, sizeof(server_msg));
			n = read(s, server_msg, PACKET_SIZE_MAX);
			if(n == 0)
			{
				close(s);
				goto FX_EXIT;
			}
		}
		
		//Get file start///////////////////////////////////////////
		packet_cnt++;
		if(strstr(server_msg, "HTTP/1.1 200 OK") || strstr(server_msg, "HTTP/1.0 200 OK"))
		{
			if(packet_cnt==1 && n < PACKET_SIZE_MAX)
			{
				writesize = Content_Length = atoi(strstr(server_msg,"Content-Length: ")+strlen("Content-Length: "));
				
				ptr1 = strstr(server_msg,"\r\n\r\n")+strlen("\r\n\r\n");
				writeFile(ptr1,Content_Length,path,"w");
				if(writesize<PACKET_SIZE_MAX)
					set_tv(&tv,2,0);
			}
			else if(packet_cnt==1 && n == PACKET_SIZE_MAX)
			{
				writesize = Content_Length = atoi(strstr(server_msg,"Content-Length: ")+strlen("Content-Length: "));
				
				ptr1 = strstr(server_msg,"\r\n\r\n")+strlen("\r\n\r\n");
				unlink(path);
				writeFile(ptr1,(PACKET_SIZE_MAX-(ptr1-server_msg)),path,"a+");
			}
			else{
				writeFile(server_msg,n,path,"a+");
			}
		}
		/*else if(strstr(server_msg, "404 Not Found"))
		{
			close(s);
			printf("    404 Not Found\n");
			unlink(path);
			goto FX_EXIT;	
		}*/
		else{
			writeFile(server_msg,n,path,"a+");
			if(packet_cnt != 1 && n != PACKET_SIZE_MAX)
				set_tv(&tv,2,0);
		}
		
	}
	
FX_EXIT:
	if( server_msg){
		free(server_msg);
	}
	return 1;
}

void getValueByServerVar(char *src,char *var,char *ret)
{
	char *p1=NULL;
	
	p1 = strstr(src,var)+strlen(var);
	strcpy(ret,p1);
	p1 = strchr(ret,'\n');
	*p1 = 0;
}

int read_server(int s,char *path)
{
	int n, ret = 0, err = 0,h=0;
	char *server_msg = NULL;
	char url[128],ver[128],size[128];
	fd_set t_set1;
	struct timeval tv;
	char filebuf[500];
	int filelen=0;
	
	server_msg = malloc(PACKET_SIZE_MAX);
	if( server_msg == NULL ){
		err = -6;
		ret = -1;
		goto FX_EXIT;
	}
	
	set_tv(&tv,5,0);
	
	FD_ZERO(&t_set1);
	FD_SET(s, &t_set1);
	
	sleep(1);
	while(1)
	{
		h= select(s+1, &t_set1, NULL, NULL, &tv);
		if(h<=0)
		{
			close(s);
			goto FX_EXIT;
		}
		if(h>0)
		{
			memset(server_msg, 0, sizeof(server_msg));
			n = read(s, server_msg, PACKET_SIZE_MAX);
			if(n == 0)
			{
				close(s);
				goto FX_EXIT;
			}
		}
		//handle/////////////////////////////////////////////////
		if(strstr(server_msg, "HTTP/1.1 200 OK") || strstr(server_msg, "HTTP/1.0 200 OK")){
			if(strstr(server_msg, "200 1 firmware file available")){
				getValueByServerVar(server_msg,"du=",url);
				getValueByServerVar(server_msg,"vn=",ver);
				getValueByServerVar(server_msg,"fs=",size);
				
				sprintf(filebuf,
				"<url>%s</url>\r\n"
				"<ver>%s</ver>\r\n"
				"<size>%s</size>\r\n",
				url,ver,size);
				filelen = strlen(filebuf);
				writeFile(filebuf,filelen,path,"w");
			}
		}
	}
	
FX_EXIT:
	if( server_msg){
		free(server_msg);
	}
	return 1;	
}

int request_server(int s, char *hostname, char *cmd)
{
	int ret = 0, err = 0;
	char *message = NULL;
        
	message = malloc(PACKET_SIZE_MAX);
	if( message == NULL ){
		err = -6;
		ret = -1;
		goto FX_EXIT;
	}
	memset(message, 0, PACKET_SIZE_MAX);
	
	(void)snprintf(message, BUFLEN, 
		"GET %s HTTP/1.1\r\n"
		"Host: %s\r\n"
		"Connection: keep-alive\r\n"
		"User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/535.19\r\n"
		"\r\n\r\n"
		,cmd,hostname);
	if(write(s, message, strlen(message)) == -1) {
		err = -1;
		ret = -1;
		goto FX_EXIT;
	}
	
FX_EXIT:
	if( message != NULL ){
		printf("    request_server() success\n");
		free(message);
	}
	if( ret < 0 ){
		printf("request_server:error(%d), sock:%d\n", err,s);
	}
	return ret;
}

int request2server(char *argv[])
{
	int s,port=80;
	char *hostname=NULL,*cmd=NULL,*path;
	hostname = argv[2];
	port = atoi(argv[3]);
	cmd = argv[4];
	path = argv[5];
	
	s = connect_http(hostname,port);
	if(s < 0){
		printf("    connect_http() error.\n");
		return -2;
	}
	if(request_server(s,hostname,cmd)<0){
		printf("    request_server() error.\n");
		close(s);
		return -3;
	}
	if(read_server(s,path)<0){
		printf("    read_server() error.\n");
		close(s);
		return -3;
	}
	
	return 1;
}

int main(int argc, char *argv[])
{
	int s;
	char *hostname = NULL, *file = NULL, *path=NULL;
	int port = 80;
	char tmpPath[30]="";
	
	if(!strcmp(argv[1],"-r")||!strcmp(argv[1],"-request")){
		request2server(argv);
		return 2;
	}
	
	if(argc < 5){
		printf("arg error\n");
		return -1;
	}
	
	hostname = argv[1];
	port = atoi(argv[2]);
	file = argv[3];
	if(argc == 4)
		path = file;
	if(argc == 5)
		path = argv[4];
	
	s = connect_http(hostname,port);
	if(s < 0){
		printf("    connect_http() error.\n");
		return -2;
	}
	
	if(request_http(s,hostname,file) < 0){
		printf("    request_http() error.\n");
		close(s);
		return -3;
	}
	
	sprintf(tmpPath,"%s.tmp",path);
	if(read_http(s,tmpPath) < 0){
		printf("    read_http() error.\n");
		close(s);
		return -4;
	}
	
	if(writesize){
		char cmd[100];
		
		if(writedsize < writesize)
			printf("\n    Get fail %s/%s ,size %d bytes\n",hostname,file,writedsize);
		else
			printf("\n    Get %s/%s ,size %d bytes\n",hostname,file,writedsize);
		close(s);
#if 0
		sprintf(cmd,"mv %s.tmp %s",path,path);
		system(cmd);
#else
		rename(tmpPath,path);
#endif
		chmod(path,S_IRUSR|S_IWUSR|S_IXUSR);
		return 1;
	}
	else{
		printf("    Get error...............\n");
		close(s);
		unlink(tmpPath);
		return -5;
	}
	
}
